/**
* TNTConcept Easy Enterprise Management by Autentia Real Bussiness Solution S.L.
* Copyright (C) 2007 Autentia Real Bussiness Solution S.L.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.autentia.tnt.tracking.annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import com.autentia.tnt.tracking.Tracking;
import com.autentia.tnt.tracking.exception.TrackingChangesException;
@Aspect
public class ChangesHistoryAspect {
/** Logger */
private static final Log log = LogFactory
.getLog(ChangesHistoryAspect.class);
private final static String FIELD_KEY = "fieldName";
private final static String METHOD_KEY = "method";
/**
* Interception method that add current changes for history to the target object
* @param call
*/
@Before("@annotation(com.autentia.tnt.tracking.annotation.ChangesHistory)")
public void addEntityChange(JoinPoint call) {
if (isTrackingActive(call)) {
try {
Properties props = this.getAnnotationProperties(call);
String methodName = props.getProperty(METHOD_KEY);
String fieldName = props.getProperty(FIELD_KEY);
Object[] args = call.getArgs();
if (args.length != 1) {
throw new TrackingChangesException(
"Invalid number of arguments.");
}
Object newObject = args[0];
Method metodo = getCallMethod(call);
String setter = metodo.getName();
if (!setter.startsWith("set")) {
throw new TrackingChangesException("Invalid setter method.");
}
String getterName = setter.substring(3);
getterName = "get" + getterName;
Method getter = getMethod(call, getterName);
Object callObject = call.getTarget();
Object[] argsMethod = {};
Object oldObject = getter.invoke(callObject, argsMethod);
String oldValue = "";
String newValue = "";
Method method = getSetterArgsClass(call)[0]
.getMethod(methodName);
if (oldObject != null) {
Object returnObject = method.invoke(oldObject, argsMethod);
if (returnObject != null) {
oldValue = returnObject.toString();
}
}
if (newObject != null) {
Object returnObject = method.invoke(newObject, argsMethod);
if (returnObject != null) {
newValue = returnObject.toString();
}
}
((Tracking) callObject).addEntityChange(fieldName, oldValue,
newValue);
} catch (SecurityException e) {
log.error("Could not track changes", e);
} catch (NoSuchMethodException e) {
log.error("Could not track changes", e);
} catch (IllegalAccessException e) {
log.error("Could not track changes", e);
} catch (InvocationTargetException e) {
log.error("Could not track changes", e);
} catch (TrackingChangesException e) {
log.error("Could not track changes", e);
}
}
}
/**
* checks if the target object has changes tracking active
* @param call
* @return
*/
private boolean isTrackingActive(JoinPoint call) {
try{
Tracking tracking = (Tracking)call.getTarget();
return tracking.isTrackingActive();
}catch(ClassCastException e){
log.error("Intercepted object is not a Tracking object", e);
return false;
}
}
/**
* returns an array with the classes of the arguments of the setter method
* @param call
* @return
*/
private Class[] getSetterArgsClass(JoinPoint call) {
Method metodo = getCallMethod(call);
Class[] params = metodo.getParameterTypes();
return params;
}
/**
* return the method with no arguments of the target object class with the name passed
* @param call
* @param methodName
* @return
* @throws SecurityException
* @throws NoSuchMethodException
*/
private Method getMethod(JoinPoint call, String methodName)
throws SecurityException, NoSuchMethodException {
Method metodo = null;
Signature sig = call.getSignature();
Class clase = sig.getDeclaringType();
Class[] args = {};
metodo = clase.getMethod(methodName, args);
return metodo;
}
/**
* @return Devuelve un properties con los atributos de la anotaciĆ³n
* @throws NoSuchMethodException
* @throws SecurityException
* @throws ClassNotFoundException
*/
private Properties getAnnotationProperties(JoinPoint call)
throws SecurityException, NoSuchMethodException {
Properties properties = new Properties();
Method metodo = this.getCallMethod(call);
ChangesHistory anotacion = metodo.getAnnotation(ChangesHistory.class);
properties.put(FIELD_KEY, anotacion.fieldName());
properties.put(METHOD_KEY, anotacion.method());
return properties;
}
/**
* Returns the intercepted method
* @param call
* @return
*/
private Method getCallMethod(JoinPoint call) {
Method metodo = null;
MethodSignature sig = (MethodSignature) call.getSignature();
metodo = sig.getMethod();
return metodo;
}
}